/* pluck 9.14 :: Thadeus Frazier-Reed c.2004

tcfr33@yahoo.com
http://music.calarts.edu/~tcfr33

//this is the one
// -- added tablesize change to object arg
*/

#include "ext.h"
#include "z_dsp.h"
#include <math.h>
#include <stdlib.h>
#include <time.h>

#define TABLESIZE 1000

typedef struct pluck
{
	t_pxobject x_ob;
	
	float *table1;
	float *delaytable;
	float *feedback;
	
	int delay1;
	int phase1;
	int count;
	
	int tablesize;
	
	time_t seconds;
	
	void *audio_out;
	
} t_pluck;	

void *pluck_class;

t_int *pluck_perform(t_int *w);
void pluck_dsp(t_pluck *x, t_signal **sp);
void pluck_dsp_free(t_pluck *x);

void pluck_bang(t_pluck *x);
void pluck_int(t_pluck *x, long n);

void *pluck_new(long arg1);

//----------------------------------
//main
void main(void)
{
	setup((t_messlist **)&pluck_class, (method)pluck_new, (method)pluck_dsp_free, (short)sizeof(t_pluck), 0L, A_DEFLONG, 0);
	addbang((method)pluck_bang);
	addint((method)pluck_int);
	addmess((method)pluck_dsp, "dsp", A_CANT, 0);
	dsp_initclass();	
}  

//-------------------------------------------------
//new
void *pluck_new(long arg1)
{
	t_pluck *x = (t_pluck *)newobject(pluck_class);
	
	dsp_setup((t_pxobject *)x, 0);
	
	outlet_new((t_object *)x, "signal");
	
	x->phase1 = 0;
	x->count = 0;
	
	if (arg1 == 0)
		x->tablesize = TABLESIZE;
	else
		x->tablesize = arg1;	
	
	x->delay1 = x->tablesize/2;
	
	x->table1 = (float*)t_getbytes((x->tablesize) * sizeof(float));
	x->delaytable = (float*)t_getbytes((x->tablesize) * sizeof(float));
	x->feedback = (float*)t_getbytes((x->tablesize) * sizeof(float));
	
	post("i'm alive");

	return(x);
		
}	
//-----------------------------------
//int
void pluck_int(t_pluck *x, long n)
{
	x->delay1 = n;
}
//-----------------------------------
//bang
void pluck_bang(t_pluck *x)
{
	int  i;
	
	time(&x->seconds);												// read clock time
	srand((unsigned int)x->seconds);								// seed random
	
	for (i=0; i<x->tablesize; i++)
		{ 
			x->table1[i] = (rand()%100);
			x->table1[i] = (x->table1[i]/50.00) - 1;		// for range -1 to 1
			x->delaytable[i] = 0;
			x->feedback[i] = 0;
		}
		
	post("bang, bang");
}

//-------------------------------------------------
//perform
t_int *pluck_perform(t_int *w)
{
	t_float *out1 = (t_float *)(w[1]);
	t_pluck *x = (t_pluck *)(w[2]);
	int n = (int)(w[3]);	
	
	while (--n) 
	{
		x->delaytable[x->delay1] = x->table1[x->phase1] + (x->feedback[x->phase1] * 0.99);
		
	 	*++out1 = x->delaytable[x->phase1];
	 	
	 	x->feedback[x->phase1] = x->delaytable[x->phase1];
	 	
	 	
		x->phase1 += 1;				// play at 44100 
		x->delay1 += 1;
		x->count += 1;
		
		// check phases 
		while (x->phase1 >= x->tablesize)
		{
			x->phase1 -=  x->tablesize; 
		}
		while (x->phase1<0)
		{
			x->phase1 += x->tablesize;
		}
		while (x->delay1 >= x->tablesize)
		{
			x->delay1 -=  x->tablesize; 
		}
		while (x->delay1<0)
		{
			x->delay1 += x->tablesize;
		}
	}
 
out:
    return (w+4);	
}
//-------------------------------------------------
//dsp
void pluck_dsp(t_pluck *x, t_signal **sp)
{
	dsp_add(pluck_perform, 3, sp[0]->s_vec, x, sp[0]->s_n ); 
	 	
}
//----------------------------------
// dsp free

void pluck_dsp_free(t_pluck *x)
{
	t_freebytes(x->table1, x->tablesize * sizeof(float));
	t_freebytes(x->delaytable, x->tablesize * sizeof(float));
	t_freebytes(x->feedback, x->tablesize * sizeof(float));
	dsp_free((t_pxobject *) x);
}